home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
language
/
xscheme.arc
/
xscom.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-01-29
|
33KB
|
1,453 lines
/* xscom.c - a simple scheme bytecode compiler */
/* Copyright (c) 1988, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use */
#include "xscheme.h"
#include "xsbcode.h"
/* size of code buffer */
#define CMAX 4000
/* continuation types */
#define C_RETURN -1
#define C_NEXT -2
/* macro to check for a lambda list keyword */
#define lambdakey(x) ((x) == lk_optional || (x) == lk_rest)
/* external variables */
extern LVAL lk_optional,lk_rest,true;
/* local variables */
static LVAL info; /* compiler info */
/* code buffer */
static unsigned char cbuff[CMAX]; /* base of code buffer */
static int cbase; /* base for current function */
static int cptr; /* code buffer pointer */
/* forward declarations */
int do_define(),do_set(),do_quote(),do_lambda(),do_consstream(),do_delay();
int do_let(),do_letrec(),do_letstar(),do_cond(),do_and(),do_or();
int do_if(),do_begin(),do_while(),do_access();
LVAL make_code_object();
/* integrable function table */
typedef struct { char *nt_name; int nt_code,nt_args; } NTDEF;
static NTDEF *nptr,ntab[] = {
"ATOM", OP_ATOM, 1,
"EQ?", OP_EQ, 2,
"NULL?", OP_NULL, 1,
"NOT", OP_NULL, 1,
"CONS", OP_CONS, 2,
"CAR", OP_CAR, 1,
"CDR", OP_CDR, 1,
"SET-CAR!", OP_SETCAR, 2,
"SET-CDR!", OP_SETCDR, 2,
"+", OP_ADD, -2,
"-", OP_SUB, -2,
"*", OP_MUL, -2,
"QUOTIENT", OP_QUO, -2,
"<", OP_LSS, -2,
"=", OP_EQL, -2,
">", OP_GTR, -2,
0
};
/* special form table */
typedef struct { char *ft_name; int (*ft_fcn)(); } FTDEF;
static FTDEF *fptr,ftab[] = {
"QUOTE", do_quote,
"LAMBDA", do_lambda,
"DELAY", do_delay,
"LET", do_let,
"LET*", do_letstar,
"LETREC", do_letrec,
"DEFINE", do_define,
"SET!", do_set,
"IF", do_if,
"COND", do_cond,
"BEGIN", do_begin,
"SEQUENCE", do_begin,
"AND", do_and,
"OR", do_or,
"WHILE", do_while,
"ACCESS", do_access,
0
};
/* xlcompile - compile an expression */
LVAL xlcompile(expr,ctenv)
LVAL expr,ctenv;
{
/* initialize the compile time environment */
info = cons(NIL,NIL); cpush(info);
rplaca(info,newframe(ctenv,1));
rplacd(info,cons(NIL,NIL));
/* setup the base of the code for this function */
cbase = cptr = 0;
/* setup the entry code */
putcbyte(OP_FRAME);
putcbyte(1);
/* compile the expression */
do_expr(expr,C_RETURN);
/* build the code object */
settop(make_code_object(NIL));
return (pop());
}
/* xlfunction - compile a function */
LVAL xlfunction(fun,fargs,body,ctenv)
LVAL fun,fargs,body,ctenv;
{
/* initialize the compile time environment */
info = cons(NIL,NIL); cpush(info);
rplaca(info,newframe(ctenv,1));
rplacd(info,cons(NIL,NIL));
/* setup the base of the code for this function */
cbase = cptr = 0;
/* compile the lambda list and the function body */
parse_lambda_list(fargs,body);
do_begin(body,C_RETURN);
/* build the code object */
settop(make_code_object(fun));
return (pop());
}
/* do_expr - compile an expression */
LOCAL do_expr(expr,cont)
LVAL expr; int cont;
{
LVAL fun;
if (consp(expr)) {
fun = car(expr);
if (!symbolp(fun) || (!in_ntab(expr,cont) && !in_ftab(expr,cont)))
do_call(expr,cont);
}
else if (symbolp(expr))
do_identifier(expr,cont);
else
do_literal(expr,cont);
}
/* in_ntab - check for a function in ntab */
LOCAL int in_ntab(expr,cont)
LVAL expr; int cont;
{
unsigned char *pname;
pname = getstring(getpname(car(expr)));
for (nptr = ntab; nptr->nt_name; ++nptr)
if (strcmp(pname,nptr->nt_name) == 0) {
do_nary(nptr->nt_code,nptr->nt_args,expr,cont);
return (TRUE);
}
return (FALSE);
}
/* in_ftab - check for a function in ftab */
LOCAL int in_ftab(expr,cont)
LVAL expr; int cont;
{
unsigned char *pname;
pname = getstring(getpname(car(expr)));
for (fptr = ftab; fptr->ft_name; ++fptr)
if (strcmp(pname,fptr->ft_name) == 0) {
(*fptr->ft_fcn)(cdr(expr),cont);
return (TRUE);
}
return (FALSE);
}
/* do_define - handle the (DEFINE ... ) expression */
LOCAL do_define(form,cont)
LVAL form; int cont;
{
if (atom(form))
xlerror("expecting symbol or function template",form);
define1(car(form),cdr(form),cont);
}
/* define1 - helper routine for do_define */
LOCAL define1(list,body,cont)
LVAL list,body; int cont;
{
LVAL fargs;
int off;
/* handle nested definitions */
if (consp(list)) {
cpush(cons(xlenter("LAMBDA"),NIL)); /* (LAMBDA) */
rplacd(top(),cons(cdr(list),NIL)); /* (LAMBDA args) */
rplacd(cdr(top()),body); /* (LAMBDA args body) */
settop(cons(top(),NIL)); /* ((LAMBDA args body)) */
define1(car(list),top(),cont);
drop(1);
}
/* compile procedure definitions */
else {
/* make sure it's a symbol */
if (!symbolp(list))
xlerror("expecting a symbol",list);
/* check for a procedure definition */
if (consp(body)
&& consp(car(body))
&& car(car(body)) == xlenter("LAMBDA")) {
fargs = car(cdr(car(body)));
body = cdr(cdr(car(body)));
cd_fundefinition(list,fargs,body);
}
/* compile the value expression or procedure body */
else
do_begin(body,C_NEXT);
/* define the variable value */
if (findcvariable(list,&off))
cd_evariable(OP_ESET,0,off);
else
cd_variable(OP_GSET,list);
do_literal(list,cont);
}
}
/* do_set - compile the (SET! ... ) expression */
LOCAL do_set(form,cont)
LVAL form; int cont;
{
if (atom(form))
xlerror("expecting symbol or ACCESS form",form);
else if (symbolp(car(form)))
do_setvar(form,cont);
else if (consp(car(form)))
do_setaccess(form,cont);
else
xlerror("expecting symbol or ACCESS form",form);
}
/* do_setvar - compile the (SET! var value) expression */
LOCAL do_setvar(form,cont)
LVAL form; int cont;
{
int lev,off;
LVAL sym;
/* get the variable name */
sym = car(form);
/* compile the value expression */
form = cdr(form);
if (atom(form))
xlerror("expecting value expression",form);
do_expr(car(form),C_NEXT);
/* set the variable value */
if (findvariable(sym,&lev,&off))
cd_evariable(OP_ESET,lev,off);
else
cd_variable(OP_GSET,sym);
do_continuation(cont);
}
/* do_quote - compile the (QUOTE ... ) expression */
LOCAL do_quote(form,cont)
LVAL form; int cont;
{
if (atom(form))
xlerror("expecting quoted expression",form);
do_literal(car(form),cont);
}
/* do_lambda - compile the (LAMBDA ... ) expression */
LOCAL do_lambda(form,cont)
LVAL form; int cont;
{
if (atom(form))
xlerror("expecting argument list",form);
cd_fundefinition(NIL,car(form),cdr(form));
do_continuation(cont);
}
/* cd_fundefinition - compile the function */
LOCAL cd_fundefinition(fun,fargs,body)
LVAL fun,fargs,body;
{
int oldcbase;
/* establish a new environment frame */
oldcbase = add_level();
/* compile the lambda list and the function body */
parse_lambda_list(fargs,body);
do_begin(body,C_RETURN);
/* build the code object */
cpush(make_code_object(fun));
/* restore the previous environment */
remove_level(oldcbase);
/* compile code to create a closure */
do_literal(pop(),C_NEXT);
putcbyte(OP_CLOSE);
}
/* parse_lambda_list - parse the formal argument list */
LOCAL parse_lambda_list(fargs,body)
LVAL fargs,body;
{
LVAL arg,restarg,new,last;
int frame,slotn;
/* setup the entry code */
putcbyte(OP_FRAME);
frame = putcbyte(0);
/* initialize the argument name list and slot number */
restarg = last = NIL;
slotn = 1;
/* handle each required argument */
while (consp(fargs) && (arg = car(fargs)) && !lambdakey(arg)) {
/* make sure the argument is a symbol */
if (!symbolp(arg))
xlerror("variable must be a symbol",arg);
/* add the argument name to the name list */
new = cons(arg,NIL);
if (last) rplacd(last,new);
else setelement(car(car(info)),0,new);
last = new;
/* generate an instruction to move the argument into the frame */
putcbyte(OP_MVARG);
putcbyte(slotn++);
/* move the formal argument list pointer ahead */
fargs = cdr(fargs);
}
/*